#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <event.h>
#include <event2/listener.h>
#include "ikcp.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define LOCAL_IP "0.0.0.0"
#define LOCAL_PORT 10000

#define REMOTE_IP "127.0.0.2"
#define REMOTE_PORT 10001

#define CLOUD_IP "8.136.212.67"
#define CLOUD_PORT 6002

#define BUF_SIZE 2048

static int pFile = 0;

static ikcpcb *kcp1;

static int sock_fd;
static struct sockaddr_in remote_addr;
static struct sockaddr_in cloud_addr;
static struct sockaddr_in local_addr;

static struct event kcpUpdateEvt;
static struct timeval kcpupdatetv = {.tv_sec = 0, .tv_usec = 10000}; //10ms的更新周期

static int initKCP();

static long long iclock64()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return ((long long)tv.tv_sec * 1000000 + tv.tv_usec);
}

static inline IUINT32 iclock()
{
    return (IUINT32)(iclock64() & 0xfffffffful);
}

void read_cb(int fd, short event, void *arg)
{
    char buf[BUF_SIZE];
    int len;
    int size = sizeof(struct sockaddr);
    struct sockaddr_in raddr;

    memset(buf, 0, sizeof(buf));
    len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&raddr, &size);

    if (len == -1)
    {
        perror("recvfrom()");
    }
    else if (len == 0)
    {
        printf("Connection Closed\n");
    }
    else
    {
        char *tmp = strstr(buf + 24, "CONNECT-12381289370120397");
        if (tmp)
        {
            static unsigned char __keybuf[128] = "";
            if (strstr(__keybuf, tmp))
            {
                //
            }
            else
            {
                snprintf(__keybuf, sizeof(__keybuf), "%s", tmp);
                ikcp_release(kcp1);
                initKCP();
                printf("KCP RESET \n");
            }
        }

        //printf("Read: len [%d] – content []\n", len);

        /* Echo */
        //sendto(fd, buf, len, 0, (struct sockaddr *)&client_addr, size);
        int hr;

        hr = ikcp_input(kcp1, buf, len);
        while (1)
        {
            hr = ikcp_recv(kcp1, buf, BUF_SIZE);
            // 没有收到包就退出
            //printf("1nrcv_que = %d innsnd_que = %d nrcv_buf = %d,nsnd_buf = %d\r\n",kcp1->nrcv_que,kcp1->nsnd_que,kcp1->nrcv_buf,kcp1->nsnd_buf);
            if (hr <= 0)
                break;
            else
            {
                //printf("1nrcv_que = %d innsnd_que = %d nrcv_buf = %d,nsnd_buf = %d\r\n", kcp1->nrcv_que, kcp1->nsnd_que, kcp1->nrcv_buf, kcp1->nsnd_buf);
                if (strstr(buf, "start-01287309217468364123749"))
                {
                    printf("recv start\n");
#if 1
                    if (pFile == 0)
                    {
                        printf("openfile\n");
                        //fp = fopen("/tmp/test.txt", "w+");
                        remove("./xxx");
                        pFile = open("./xxx", O_CREAT | O_RDWR, 0644);
                    }
                    else
                    {
                        close(pFile);
                        pFile = 0;
                    }
#endif
                }
                else if (strstr(buf, "end-01287309217468364123749"))
                {

#if 1

                    if (pFile > 0)
                    {
                        printf("recv finish\n");
                        close(pFile);

                        system("md5sum ./xxx");

                        pFile = 0;
                    }
#endif
                }
                else
                {

#if 1
                    if (pFile > 0)
                    {
                        //printf("write %d\n", hr);
                        write(pFile, buf, hr);
                    }
#endif
                }
            }
        }
    }
}

// 定时事件回调函数
void kcpUpdateTmr(int sock, short event, void *arg)
{
    static unsigned int cnt = 0;

    cnt++;
    if (cnt == (1000 / 10))
    {
        printf("send cloud ping\n");
        sendto(sock_fd, "1", 1, 0, (struct sockaddr *)&cloud_addr, sizeof(struct sockaddr_in));
        cnt = 0;
    }
    ikcp_update(kcp1, iclock());
    event_add((struct event *)arg, &kcpupdatetv);
}

int bind_socket(struct event *ev)
{

    int flag = 1;
    struct sockaddr_in sin;

    /* Create endpoint */
    if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket()");
        return -1;
    }

    /* Set socket option */
    if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)) < 0)
    {
        perror("setsockopt()");
        return 1;
    }

    /* Set IP, port */
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(LOCAL_IP);
    sin.sin_port = htons(LOCAL_PORT);

    /* Bind */
    if (bind(sock_fd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0)
    {
        perror("bind()");
        return -1;
    }
    else
    {
        printf("bind() success – [%s] [%u]\n", LOCAL_IP, LOCAL_PORT);
    }

    /* Init one event and add to active events */
    event_set(ev, sock_fd, EV_READ | EV_PERSIST, &read_cb, NULL);
    if (event_add(ev, NULL) == -1)
    {
        printf("event_add() failed\n");
    }

    return 0;
}

// 模拟网络：模拟发送一个 udp包
int udp_output(const char *buf, int len, ikcpcb *kcp, void *user)
{
    //union { int id; void *ptr; } parameter;
    //parameter.ptr = user;

    //printf("udp_output:11\n");
    sendto(sock_fd, buf, len, 0, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr_in));
    sendto(sock_fd, buf, len, 0, (struct sockaddr *)&cloud_addr, sizeof(struct sockaddr_in));

    return 0;
}

static int initKCP()
{
    kcp1 = ikcp_create(0x11223344, (void *)0);

    // 设置kcp的下层输出，这里为 udp_output，模拟udp网络输出函数
    //kcp1->output = udp_output;
    ikcp_setoutput(kcp1, udp_output);

    // 配置窗口大小：平均延迟200ms，每20ms发送一个包，
    // 而考虑到丢包重发，设置最大收发窗口为128
    ikcp_wndsize(kcp1, 2048, 2048);

    // 启动快速模式
    // 第二个参数 nodelay-启用以后若干常规加速将启动
    // 第三个参数 interval为内部处理时钟，默认设置为 10ms
    // 第四个参数 resend为快速重传指标，设置为2
    // 第五个参数 为是否禁用常规流控，这里禁止
    ikcp_nodelay(kcp1, 1, 10, 2, 1);
    kcp1->rx_minrto = 10;
    kcp1->fastresend = 1;

    return 0;
}

int main(void)
{
    static pthread_t sendertid;
    struct event evTime;
    struct event ev;

    memset(&remote_addr, 0, sizeof(remote_addr));
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_addr.s_addr = inet_addr(REMOTE_IP);
    remote_addr.sin_port = htons(REMOTE_PORT);

    memset(&cloud_addr, 0, sizeof(cloud_addr));
    cloud_addr.sin_family = AF_INET;
    cloud_addr.sin_addr.s_addr = inet_addr(CLOUD_IP);
    cloud_addr.sin_port = htons(CLOUD_PORT);

    /*初始化kcp协议栈*/
    initKCP();

    /* Init. event */
    if (event_init() == NULL)
    {
        printf("event_init() failed\n");
        return -1;
    }

    /* EVENT TIMER*/
    evtimer_set(&kcpUpdateEvt, kcpUpdateTmr, &kcpUpdateEvt);
    evtimer_add(&kcpUpdateEvt, &kcpupdatetv);

    /* Bind socket */
    if (bind_socket(&ev) != 0)
    {
        printf("bind_socket() failed\n");
        return -1;
    }

    /* Enter event loop */
    event_dispatch();

    return 0;
}
